react-cropper结合Antd Upload实现图片裁剪并上传

cropper文档

cropperjs

react-cropper

cropperjs翻译文档:cropper.js 裁剪图片并上传(文档翻译+demo)

install

1
yarn add react-cropper
1
2
import Cropper from 'react-cropper'
import 'cropperjs/dist/cropper.css'

主要配置说明

viewMode 配置视图模式

  • 0:无限制
  • 1:限制裁剪框不能超出图片的范围
  • 2:限制裁剪框不能超出图片的范围,且图片填充模式为最长边填充
  • 3:限制裁剪框不能超出图片的范围,且图片填充模式为最短边填充

dragMode 配置拖拽模式

  • crop:拖拽形成新的裁剪框
  • move:拖拽只能移动图片
  • none:不做处理

主要方法说明

onInitialized 获取cropper实例

1
onInitialized={(instance) => {cropper.current = instance}}

zoom 缩放事件

zoom监听事件中限制最大最小缩放比例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const zoom = (e) => {
const { ratio, oldRatio } = e.detail
// zoom in
if (ratio > oldRatio) {
if (ratio > maxRatio) {
e.preventDefault()
cropper.current.zoomTo(maxRatio)
}
// zoom out
} else if (ratio < oldRatio) {
if (ratio < minRatio) {
e.preventDefault()
cropper.current.zoomTo(minRatio)
}
}
}

getCanvasData 获取裁剪的图片数据

toBlob

toBlob第二个参数默认是image/png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const getCroppedData = () => {
return new Promise((resolve, reject) => {
try {
cropper.current.getCroppedCanvas({
// ...
imageSmoothingQuality: 'high',
}).toBlob((blob) => {
resolve(blob)
}, 'image/jpeg')
} catch (e) {
reject()
}
})
}

toDataURL

1
cropper.current.getCroppedCanvas().toDataURL('image/jpeg')

实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<Cropper
src={image}
dragMode="move"
minCropBoxWidth={cropWidth}
minCropBoxHeight={cropHeight}
viewMode={3}
guides={false}
center={false}
checkOrientation={false}
background={false}
modal={false}
toggleDragModeOnDblclick={false}
cropBoxMovable={false} // 是否通过拖拽来移动剪裁框
cropBoxResizable={false} // 是否通过拖动来调整剪裁框的大小
onInitialized={initial}
zoom={zoom}
style={style}
/>

结合Antd Upload裁剪并上传图片

beforeUpload返回Promise。在beforeUpload方法中,将得到的图片文件转成DataURL传给裁剪组件。设置定时器,每隔一段时间查询裁剪是否完成,若裁剪完成则resolve(croppedFile)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const beforeUpload = (file) => {
return new Promise((resolve, reject) => {
imageBlob.current = null

let reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = (e) => {
setCropImage(e.target.result)
}

// 定时器
timer.current = window.setInterval(() => {
// 裁剪完成
if (imageBlob.current) {
window.clearInterval(timer.current)
// blob转file
const croppedFile = new File([avatarBlob.current], file.name, {
type: 'image/jpeg',
uid: file.uid,
lastModified: Date.now(),
})
resolve(croppedFile)
}
}, 100)
})
}

Demo